from django.http import HttpResponse
from django.shortcuts import render
from django import views
from rest_framework import status
from utils.verifyUtil import VerifyUtil
from django_redis import get_redis_connection
from jt32.settings import CACHES
from config.dbs.redisConfig import KEY_TEMPLATE, EXPIRE_TIME
from rest_framework import viewsets
from django.contrib.auth.models import User
from .serializers import UserSerializer, MyTokenObtainPairSerializer, UserDetailSerializer, UpdatePasswordSerializer, \
    AreaSerializer, AreaSerializerSimple, AddressSerializer
from rest_framework.response import Response
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from fdfs_client.client import Fdfs_client, get_tracker_conf
from rest_framework_extensions.cache.mixins import CacheResponseMixin
from .models import Area, Address
import io
import logging
# Create your views here.


# 获取验证码
class ImageVerifyView(views.View):
    # 使用get方法
    def get(self, request, func, uuid):
        # 实例化验证码对象
        verify_util = VerifyUtil()
        # 获取验证码图片和验证码
        img, code = verify_util.create_verify_img()
        # 字节流临时处理
        img_bytes = io.BytesIO()
        img.save(img_bytes, 'png')
        img_bytes = img_bytes.getvalue()
        # redis数字库进行保存
        cache = get_redis_connection(alias='verify_codes')
        # 存入redis数据库
        cache.set(KEY_TEMPLATE % (func, uuid), code, EXPIRE_TIME)
        # 返回数据
        return HttpResponse(img_bytes, content_type='image/png')


# 点击注册执行类
class UserViewSet(viewsets.GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # 权限方法
    def get_permissions(self):
        if self.action in ['now', 'info', 'password']:
            permission_classes = [IsAuthenticated]
        else:
            permission_classes = []
        return [permission() for permission in permission_classes]

    # 根据情况重写序列化器
    def get_serializer_class(self):
        if self.action == 'info':
            return UserDetailSerializer
        elif self.action == 'password':
            return UpdatePasswordSerializer
        else:
            return UserSerializer

    # 重写create方法,因为用的是系统自带的auth表,没有序列器中的verify和uuid字段
    def create(self, request, *args, **kwargs):
        # 反序列化并进行校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 重新获取用户名,密码
        username = request.data.get('username')
        password = request.data.get('password')
        # 往数据库进行存储,并且密码存入加密状态的
        user = User.objects.create(username=username)
        user.set_password(password)
        # 保存用户
        user.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    # 增加now方法,进行首页的展示
    @action(methods=['get'], detail=False)
    def now(self, request):
        # 进行数据序列化并返回给前端
        serializer = self.get_serializer(request.user)
        return Response(serializer.data)

    # 增加info方法,可以对个人信息进行修改
    @action(methods=['put'], detail=False)
    def info(self, request):
        # 获取用户传来的数据
        user = request.user
        request.POST._mutable = True
        request.data['user'] = user.id

        # 增加上头像数据的上传和展示
        client_address = get_tracker_conf('fastdfs/client.conf')
        client = Fdfs_client(client_address)
        logger = logging.getLogger(__name__)
        # 获取文件信息
        file = request.FILES.get('file')
        # 判断是否上传文件
        if file:
            # 判断文件上传格式是否规范
            if file.content_type not in ['image/png', 'image/jpeg']:
                return Response({'msg': '仅支持上传png或者jpg的格式'}, status=status.HTTP_400_BAD_REQUEST)
            # 获取文件后缀
            try:
                ext = file.name.split('.')[-1]
            # 获取失败
            except Exception as e:
                logger.info('图片扩展名异常', e)
                ext = 'png'
            # 上传到fastdfs
            try:
                upload_result = client.upload_by_buffer(file.read(), file_ext_name=ext)
            except Exception as e:
                logger.error('图片上传错误', e)
                return Response({'msg': '图片上传错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            # 判断图片是否上传成功
            if upload_result.get('Status') != 'Upload successed.':
                logger.error('图片上传失败', upload_result)
                return Response({'msg': '图片上传失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            # 判断用户详情是否已经有图片了
            if hasattr(user, 'userdetail') and user.userdetail.avatar:
                # 删除原来的图片
                try:
                    client.delete_file(user.userdetail.avatar.encode())
                except Exception as e:
                    logger.error('图片删除失败', e)
            # 得到原来头像的地址并存储至数据库
            image_url = upload_result.get('Remote file_id').decode()
            request.data['avatar'] = image_url

        # 判断用户有没有userdetail,如果有则修改,没有则进行创建
        if hasattr(user, 'userdetail'):
            serializer = self.get_serializer(instance=user.userdetail, data=request.data)
        else:
            serializer = self.get_serializer(data=request.data)
        # 对数据校验并保存
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

    # 增加password方法,可以对密码进行修改
    @action(methods=['put'], detail=False)
    def password(self, request):
        # 获取用户数据并进行序列化校验
        user = request.user
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 获得新密码并进行加密存储
        new_password = serializer.data.get('new_password')
        user.set_password(new_password)
        user.save()
        return Response({'msg': '密码修改成功'})


# 登录校验及token视图类
class MyTokenObtainPairView(TokenObtainPairView):
    # 指定序列化器
    serializer_class = MyTokenObtainPairSerializer


# 地址省市区视图类
class AreaViewSet(CacheResponseMixin, viewsets.ReadOnlyModelViewSet):
    # 指定模型和序列化器
    queryset = Area.objects.all()
    serializer_class = AreaSerializer
    # 指定登录权限
    permission_classes = [IsAuthenticated]

    # 重写模型
    def get_queryset(self):
        # 如果使用的是list方法
        if self.action == 'list':
            return self.queryset.filter(parent=None)
        else:
            return self.queryset

    # 重写序列化器
    def get_serializer_class(self):
        if self.action == 'list':
            return AreaSerializer
        else:
            return AreaSerializerSimple


# 地址详情视图类
class AddressViewSet(viewsets.ModelViewSet):
    # 模型和序列化器
    queryset = Address.objects.filter(is_delete=False)
    serializer_class = AddressSerializer
    # 登录权限
    permission_classes = [IsAuthenticated]

    # 重写模型,只进行展示自己的收获地址
    def get_queryset(self):
        # return self.request.user.address_set.filter(is_delete=False)
        return self.queryset.filter(user=self.request.user)

    # 重写create方法,防止错误添加他人的地址
    def create(self, request, *args, **kwargs):
        # 将增加的id进行指定
        request.POST._mutable = True
        request.data['user'] = request.user.id
        # 对存储的地址个数进行一定的限制(如不可以超过3个)
        if self.get_queryset().count() >= 4:
            return Response({'msg': '地址个数不能超过4个'}, status=status.HTTP_400_BAD_REQUEST)
        return viewsets.ModelViewSet.create(self, request, *args, **kwargs)

    # 重写修改方法,防止错误添加他人的地址
    def update(self, request, *args, **kwargs):
        # 将修改的id进行指定
        request.POST._mutable = True
        request.data['user'] = request.user.id
        # 直接返回父类的修改方法
        return viewsets.ModelViewSet.update(self, request, *args, **kwargs)
